package robotinfo

import (
	"context"
	"sale-admin/config/mysql"
	"sale-admin/internal/app/grpc/client"
	"sale-admin/internal/app/grpc/protoc/devicec"
	"sale-admin/internal/app/grpc/protoc/system_admin"
	"sale-admin/internal/app/web/service/common"
	"sale-admin/internal/dal"
	"sale-admin/internal/dao"
	"sale-admin/internal/models"
	"sort"
	"strconv"
	"strings"

	"192.168.1.75/go-pkg/helper"
	"192.168.1.75/go-pkg/logx"
	"github.com/samber/lo"
	"gorm.io/gorm"
)

type RobotInfoService struct{}

// 设置机器商品排序
func (r RobotInfoService) SetRobotSort(ctx context.Context, db *gorm.DB, SalesID, GoodsID string, Multi, Sort int) (err error) {
	db.Model(&models.MaRobotSalesInfo{}).
		Where("sales_id = ? and goods_id = ?", SalesID, GoodsID).
		UpdateColumn("sort", Sort)

	if Multi == 1 {
		db.Model(&models.MaGoodsMulti{}).
			Where("id = ?", GoodsID).
			UpdateColumn("multi_sort", Sort)
	}
	return
}

type MySaleInfoList struct {
	SalesID               string                   `json:"sales_id"`                     // 设备号
	GoodsID               int                      `json:"goods_id"`                     // 商品id
	GoodsMaxInventory     int                      `json:"goods_max_inventory"`          // 商品最大库存
	GoodsReserveInventory int                      `json:"goods_reserve_inventory"`      // 商品预留库存
	RobotGoodsInventory   int                      `json:"robot_goods_inventory"`        // 机器商品库存
	RobotName             string                   `json:"robot_name"`                   // 机器名称
	Data                  []MaRobotSalesInfoDetail `gorm:"-" json:"data"`                // data
	ErrorContainerNum     string                   `gorm:"-" json:"error_container_num"` // 故障货道数
	ZeroContainerNum      string                   `gorm:"-" json:"zero_container_num"`  // 零库存货道数
	Areas3                string                   `json:"areas3"`                       // 商场
	TotalRobotLast        int                      `json:"total_robot_last"`             // 机器总剩余
	MerchantID            string                   `json:"merchant_id"`                  // 商户id
	MerchantName          string                   `json:"merchant_name"`                // 商户名称
}
type MaRobotSalesInfoDetail struct {
	GoodsName1            string `json:"goods_name1"`
	GoodsID               int    `json:"goods_id"`
	SalesID               string `json:"sales_id"`
	MerchantID            string `json:"merchant_id"`
	RobotName             string `json:"robot_name"`
	Areas3                string `json:"areas3"`
	ContainerStatus       int    `json:"container_status"`
	ContainerNum          int    `json:"container_num"`           // 货道号
	TotalRobotLast        int    `json:"total_robot_last"`        // 待删除
	RobotGoodsInventory   int    `json:"robot_goods_inventory"`   // 机器商品库存
	GoodsReserveInventory int    `json:"goods_reserve_inventory"` // 商品预留库存
	GoodsMaxInventory     int    `json:"goods_max_inventory"`     // 商品最大库存
}

type HistoryInventory struct {
	GoodsName1        string  `json:"goods_name1"`
	GoodsID           int     `json:"goods_id"`
	SalesID           string  `json:"sales_id"`
	RobotName         string  `json:"robot_name"`
	Areas3            string  `json:"areas3"`
	ZeroContainerNum  string  `json:"zero_container_num"`
	ErrorContainerNum string  `json:"error_container_num"`
	GoodsInventory    int     `json:"goods_inventory"`
	GoodsMaxInventory int     `json:"goods_max_inventory"`
	Persent           float32 `json:"persent"`
	MerchantID        string  `json:"merchant_id"`
	Date              string  `json:"date"`
}

func getMerchantRobotList(merchantID string) (salesIDs []string) {
	// grpc获取该商户的机器列表
	req := &devicec.DeviceListReq{}
	if merchantID != "1" {
		req.MerchantId = merchantID
	}
	deviceClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		logx.Error(context.Background(), "grpc device client error", logx.Err(clientErr))
		return
	}
	deviceList, _ := deviceClient.DeviceList(context.Background(), req)
	for _, v := range deviceList.List {
		// if merchantID != "1" {
		// 	if v.DeviceType == 5 || v.DeviceType == 11 {
		// 		salesIDs = append(salesIDs, v.IdentificationCode)
		// 	}
		// } else {
		// 	// 过滤admin的设备
		// 	if (v.DeviceType == 5 || v.DeviceType == 11) && v.MerchantId != "1" {
		// 		salesIDs = append(salesIDs, v.IdentificationCode)
		// 	}
		// }

		if merchantID != "1" {
			//  merchantID!=1
			if v.DeviceType == 5 || v.DeviceType == 11 {
				salesIDs = append(salesIDs, v.IdentificationCode)
			}
		} else {
			// 过滤admin的设备 merchantID=1
			if (v.DeviceType == 5 || v.DeviceType == 11) && v.MerchantId != "1" {
				salesIDs = append(salesIDs, v.IdentificationCode)
			}
		}

		if (v.DeviceType == 5 || v.DeviceType == 11) && v.MerchantId != "1" {
			salesIDs = append(salesIDs, v.IdentificationCode)
		}
	}
	return salesIDs
}

func getMerchantRobotListNew(merchantID string, salesIdsSource string) (salesIDs []string) {
	// grpc获取该商户的机器列表
	req := &devicec.DeviceListReq{}
	if merchantID != "1" {
		req.MerchantId = merchantID
	}
	deviceClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		logx.Error(context.Background(), "grpc device client error", logx.Err(clientErr))
		return
	}
	deviceList, _ := deviceClient.DeviceList(context.Background(), req)

	if salesIdsSource == "" {
		//查询所有机器 不过滤商户类型为1的数据
		for _, v := range deviceList.List {
			// if v.DeviceType == 5 || v.DeviceType == 11 {
			// 	salesIDs = append(salesIDs, v.IdentificationCode)
			// }
			if (v.DeviceType == 5 || v.DeviceType == 11) && v.MerchantId != "1" {
				salesIDs = append(salesIDs, v.IdentificationCode)
			}
		}
	} else {
		// 查询特定机器 过滤掉 MerchantId=1的数据
		var salesIdsSourceList []string = strings.Split(salesIdsSource, ",")
		for _, v := range deviceList.List {
			if (v.DeviceType == 5 || v.DeviceType == 11) && v.MerchantId != "1" && in(v.IdentificationCode, salesIdsSourceList) {
				salesIDs = append(salesIDs, v.IdentificationCode)
			}
		}
	}

	return salesIDs
}

type ZeroListStruct struct {
	ID             string `json:"id"`
	Url            string `json:"url"`
	Type           int    `json:"type"`
	ZeroType       int    `json:"zero_type"`
	RobotName      string `json:"robot_name"`
	ObjectName     string `json:"object_name"`
	WebHookName    int    `json:"web_hook_name"`
	WebHookAddress string `json:"web_hook_address"`
	Object         string `json:"object"`
	CreatedAt      int64  `json:"created_at"`
}

// GetZeroStockData 获取空货数据
func (r RobotInfoService) GetZeroStockData(ctx context.Context, db *gorm.DB, merchantID string, stockType int, startTime, endTime string, page, limit int) (res []ZeroListStruct, count int64, err error) {
	list, count, err := dao.RobotReportLog{}.EmptyStockList(ctx, dal.Q, merchantID, stockType, startTime, endTime, page, limit)

	res = []ZeroListStruct{}
	for _, v := range list {
		var item ZeroListStruct
		item.ID = v.ID
		item.Url = v.Url
		item.Type = v.Type
		var zeroType int
		if v.Type == 4 {
			zeroType = 1 // 单日空货
		} else {
			zeroType = 2 // 连续空货
		}
		item.ZeroType = zeroType
		item.RobotName = v.RobotName
		item.ObjectName = v.ObjectName
		item.WebHookName = v.WebHookName
		item.WebHookAddress = v.Url
		item.Object = v.Object
		item.CreatedAt = v.CreatedAt
		res = append(res, item)
	}

	return res, count, err
}

// GetZeroStockData 获取空货数据 - 详情
func (r RobotInfoService) GetZeroStockDataDetail(ctx context.Context, db *gorm.DB, merchantID string, Type int,
	startTime, endTime, robotName string) (res []*models.MaRobotEmptyStock, err error) {
	list, _, err := dao.RobotEmptyStock{}.List(ctx, dal.Q, Type, merchantID, startTime, endTime, robotName)
	return list, err
}

// 历史库存列表之商品展开
func (r RobotInfoService) HistoryInventoryOfGoods(ctx context.Context, db *gorm.DB, merchantID, salesID, startTime, endTime string) (
	res []HistoryInventory, err error,
) {
	var HistoryInventoryData []HistoryInventory
	// 获取补货信息
	tx := db.Table(models.MaRobotInventory{}.TableName() + " as i").
		Joins(" left join " + models.MaRobot{}.TableName() + " as r on r.sales_id = i.sales_id").
		Joins(" left join " + models.MaGoodsInfo{}.TableName() + " as g on g.goods_id = i.goods_id")

	if startTime != "" && endTime != "" {
		tx.Where("i.date between ? and ?", startTime, endTime)
	}
	var salesIDs = []string{}
	if salesID == "" {
		salesIDs = getMerchantRobotList(merchantID)
	} else {
		salesIDs = strings.Split(salesID, ",")
	}
	tx.Where("r.sales_id in (?)", salesIDs)
	// 公共条件
	tx.Where("r.deleted = ?", 0)
	tx.Where("r.robot_type in (?)", []int{0, 5, 11})

	tx.Select(
		"i.date", "i.goods_id", "r.robot_name", "r.sales_id", "r.merchant_id", "r.areas3", "g.goods_name1",
		"i.goods_inventory",     // 剩余库存
		"i.goods_max_inventory", // 最大库存
		"i.error_container_num", // 错误货道
		"i.zero_container_num",  // 0货道
		"(goods_inventory/goods_max_inventory) as persent",
	).Find(&HistoryInventoryData)

	return HistoryInventoryData, err
}

// 获取0货道、故障货道信息 ------ 定时任务使用
// GetHistoryErrorContainerNums
func (r RobotInfoService) GetHistoryErrorContainerNums(ctx context.Context, query *dal.Query, salesID string) (errorContainers string, zeroContainers string, err error) {
	// 0库存货道
	zeroContainerNums, _ := dao.RobotSalesInfo{}.GetZeroContainerNumBySalesID(ctx, query, salesID)
	if len(zeroContainerNums) > 0 {
		for _, zeroContainerNum := range zeroContainerNums {
			zeroContainers += strconv.Itoa(zeroContainerNum) + ","
		}
	}
	// 故障货道
	errorContainerNums, _ := dao.RobotSalesInfo{}.GetErrorContainerNumsBySalesID(ctx, query, salesID)
	if len(errorContainerNums) > 0 {
		for _, errorContainerNum := range errorContainerNums {
			errorContainers += strconv.Itoa(errorContainerNum) + ","
		}
	}
	errorContainers = strings.Trim(errorContainers, ",")
	zeroContainers = strings.Trim(zeroContainers, ",")
	return
}

func in(target string, str_array []string) bool {
	for _, element := range str_array {
		if target == element {
			return true
		}
	}
	return false
}

// 获取补货库存信息
func (r RobotInfoService) GetInventoryBySalesid(ctx context.Context, db *gorm.DB, merchantID, salesID string, page, limit int,
) (res []MySaleInfoList, Count int64, err error) {
	var SalesDetailRes []MaRobotSalesInfoDetail
	// 获取补货信息
	tx := db.Table(models.MaRobot{}.TableName() + " as r").
		Joins(" left join " + models.MaRobotSalesInfo{}.TableName() + " as s on s.sales_id = r.sales_id and s.container_status = 1 and s.container_use_status = 1").
		Joins(" left join " + models.MaGoodsInfo{}.TableName() + " as g on g.goods_id = s.goods_id")
	var salesIDs = []string{}
	salesIDs = getMerchantRobotListNew(merchantID, salesID)
	// if salesID == "" {
	// 	salesIDs = getMerchantRobotListNew(merchantID)
	// } else {
	// 	salesIDs = strings.Split(salesID, ",")
	// }
	tx.Where("r.sales_id in (?)", salesIDs)
	// 公共条件
	tx.Where("r.deleted = ?", 0)
	tx.Where("r.robot_type in (?)", []int{0, 5, 11})

	// 查询总条数和分页返回数据
	// 机器+商品分组
	tx.Group("r.sales_id, s.goods_id").
		Select(
			"r.merchant_id", "r.sales_id", "r.robot_name", "r.areas3", "s.container_status", "s.goods_id", "g.goods_name1",
			"sum(goods_reserve_inventory) as goods_reserve_inventory",
			"sum(goods_inventory) as robot_goods_inventory",
			"sum(goods_max_inventory) as goods_max_inventory",
		).
		Order("IF(isnull(goods_max_inventory),1,0), robot_goods_inventory, goods_max_inventory").
		Find(&SalesDetailRes)
	var RobotSalesGoodsMap = make(map[string][]MaRobotSalesInfoDetail)
	for _, v := range SalesDetailRes {
		RobotSalesGoodsMap[v.RobotName] = append(RobotSalesGoodsMap[v.RobotName], v)
	}

	var MySaleInfoListSlice []MySaleInfoList
	var MySaleInfoListSliceEmpty []MySaleInfoList

	for RobotName, goodsList := range RobotSalesGoodsMap {
		maxInventory := 0
		robotGoodsInventory := 0
		goodsReserveInventory := 0
		for _, n := range goodsList {
			maxInventory += n.GoodsMaxInventory
			robotGoodsInventory += n.RobotGoodsInventory
			goodsReserveInventory += n.GoodsReserveInventory
		}
		var item MySaleInfoList
		item.RobotName = RobotName
		item.SalesID = goodsList[0].SalesID
		item.GoodsMaxInventory = maxInventory              //最大库存
		item.RobotGoodsInventory = robotGoodsInventory     //当前库存
		item.GoodsReserveInventory = goodsReserveInventory // 预留库存
		item.Data = goodsList
		item.MerchantID = goodsList[0].MerchantID

		//最大库存为0的单独分组
		if item.GoodsMaxInventory == 0 && item.RobotGoodsInventory == 0 {
			MySaleInfoListSliceEmpty = append(MySaleInfoListSliceEmpty, item)
		} else {
			MySaleInfoListSlice = append(MySaleInfoListSlice, item)
		}
	}

	sort.Slice(MySaleInfoListSlice, func(i, j int) bool {
		//	2023/08/02 最新确认规则
		//	规则1: 当前库存>最大库存；
		if MySaleInfoListSlice[i].RobotGoodsInventory != MySaleInfoListSlice[j].RobotGoodsInventory {
			return MySaleInfoListSlice[i].RobotGoodsInventory < MySaleInfoListSlice[j].RobotGoodsInventory
		} else {
			if MySaleInfoListSlice[i].GoodsMaxInventory != MySaleInfoListSlice[j].GoodsMaxInventory {
				return MySaleInfoListSlice[i].GoodsMaxInventory < MySaleInfoListSlice[j].GoodsMaxInventory
			} else {
				return MySaleInfoListSlice[i].SalesID < MySaleInfoListSlice[j].SalesID
			}
		}
	})

	//	规则2: 最大库存为0，底部；
	sort.Slice(MySaleInfoListSliceEmpty, func(i, j int) bool {
		return MySaleInfoListSliceEmpty[i].SalesID < MySaleInfoListSliceEmpty[j].SalesID
	})
	//排序后合并
	MySaleInfoListSlice = append(MySaleInfoListSlice, MySaleInfoListSliceEmpty...)
	var limitData = []MySaleInfoList{}
	if len(MySaleInfoListSlice) > 0 {
		start, end := common.SlicePage(page, limit, len(MySaleInfoListSlice))
		limitData = MySaleInfoListSlice[start:end]

		SystemAdminClient, clientErr := client.GetSystemAdminClient()
		if clientErr != nil {
			logx.Error(context.Background(), "grpc system admin client error", logx.Err(clientErr))
			err = clientErr
			return limitData, int64(len(MySaleInfoListSlice)), err
		}

		for i, _ := range limitData {
			// 根据商户ID，获取商户名称
			req := &system_admin.MerchantInfoReq{}
			req.MerchantId = limitData[i].MerchantID
			res, err := SystemAdminClient.MerchantInfo(context.Background(), req)
			if res != nil && res.Code == 0 && err == nil {
				limitData[i].MerchantName = res.MerchantName
			}
			// if len(limitData[i].Data) == 1 && limitData[i].Data[0].GoodsID == 0 {
			// 	limitData[i].Data = []MaRobotSalesInfoDetail{}
			// }
		}
	}

	return limitData, int64(len(MySaleInfoListSlice)), err
}

// 历史库存列表（后台用，展开是每台机器商品数据）
func (r RobotInfoService) HistoryInventoryBySalesid(ctx context.Context, db *gorm.DB, merchantID, salesID, startTime, endTime string, page, limit int) (res []models.MaRobotInventory, Count int64, err error) {
	var salesIDs = []string{}
	if salesID == "" && merchantID != "1" {
		salesIDs = getMerchantRobotList(merchantID)
		salesID = strings.Join(salesIDs, ",")
	}
	RobotNameList := []string{}
	if salesID != "" {
		robotList, _, _ := dao.Robot{}.RobotList(ctx, db, "", "", "", salesID, "", "", "", "")
		for _, v := range robotList {
			RobotNameList = append(RobotNameList, v.RobotName)
		}
	}
	var HistoryInventoryData = []models.MaRobotInventory{}
	// 获取补货信息
	tx := db.Table(models.MaRobotInventory{}.TableName() + " as i").
		Joins(" left join " + models.MaRobot{}.TableName() + " as r on r.robot_name = i.robot_name")

	if startTime != "" && endTime != "" {
		tx.Where("i.date between ? and ?", startTime, endTime)
	}
	if len(RobotNameList) > 0 {
		tx.Where("i.robot_name in (?)", RobotNameList)
	}
	tx.Group("i.date,i.robot_name").
		Select(
			"i.robot_name", "i.sales_id", "r.merchant_id", "r.areas3", "i.date",
			"sum(i.goods_inventory) as goods_inventory",         // 剩余库存（当前机器当日的所有商品的合计）
			"sum(i.goods_max_inventory) as goods_max_inventory", // 最大库存（当前机器当日的所有商品的合计）
			"i.error_container_num",                             // 错误货道
			"i.zero_container_num",                              // 空货道
		)
	tx.Count(&Count)
	helper.Gorm{}.Paginate(tx, page, limit).
		Order("i.date desc").
		Find(&HistoryInventoryData)
	return HistoryInventoryData, Count, err
}

// 获取补货库存信息 --- 定时任务使用，用于生成每日的历史库存
func (r RobotInfoService) GetHistoryInventoryBySalesid(db *gorm.DB) (res []MySaleInfoList, Count int64, err error) {
	var SalesDetailRes []MaRobotSalesInfoDetail
	// 获取补货信息
	db.Table(models.MaRobot{}.TableName()+" as r").
		Joins(" left join "+models.MaRobotSalesInfo{}.TableName()+" as s on s.robot_name = r.robot_name").
		Where("s.container_status = 1 and s.container_use_status = 1"). // 上架 + 正常
		Where("r.deleted = ?", 0).
		Where("r.robot_type in (?)", []int{0, 5, 11}).
		Group("r.robot_name, s.goods_id"). // 按照商品分组查询数据
		Select("r.merchant_id", "r.areas3", "s.container_status", "s.goods_id",
			"r.robot_name", "r.sales_id",
			"sum(goods_inventory) as robot_goods_inventory",   // 当前剩余库存
			"sum(goods_max_inventory) as goods_max_inventory", // 机器最大库存
		).
		Find(&SalesDetailRes)

	var robotSalesInfoDetail = make(map[string][]MaRobotSalesInfoDetail)
	for _, v := range SalesDetailRes {
		robotSalesInfoDetail[v.RobotName] = append(robotSalesInfoDetail[v.RobotName], v)
	}

	var MySaleInfoListSlice []MySaleInfoList
	for RobotName, goodsList := range robotSalesInfoDetail {
		var item MySaleInfoList
		item.MerchantID = goodsList[0].MerchantID
		item.RobotName = RobotName
		item.SalesID = goodsList[0].SalesID
		item.Data = goodsList
		MySaleInfoListSlice = append(MySaleInfoListSlice, item)
	}

	return MySaleInfoListSlice, int64(len(MySaleInfoListSlice)), err
}

// 补货记录列表
func (r RobotInfoService) RobotSaleInfoLog(
	ctx context.Context,
	salesID,
	provinceID, cityID, districtID, locationID,
	startTime, endTime string,
	Type, page, limit int,
	username string,
) (Log []*models.MaSaleInfoLog, Count int64, err error) {
	// 地区查询
	robotList, robotCount, _ := dao.Robot{}.RobotList(ctx, mysql.NewDB(), "", "", "", salesID, provinceID, cityID, locationID, districtID)
	if robotCount == 0 {
		return
	}
	var robotSalesIDs []string
	for _, v := range robotList {
		robotSalesIDs = append(robotSalesIDs, v.SalesID)
	}
	Log, Count, err = dao.SaleInfoLog{}.List(ctx, dal.Q, strings.Join(robotSalesIDs, ","), Type, startTime, endTime, page, limit, username)
	deviceClient, clientErr := client.GetDeviceAdminClient()
	if clientErr != nil {
		logx.Error(context.Background(), "grpc device client error", logx.Err(clientErr))
		return
	}
	SystemAdminClient, clientErr := client.GetSystemAdminClient()
	if clientErr != nil {
		err = clientErr
		return
	}

	LocationMap := make(map[string]string)
	AreaNameMap := make(map[string]string)
	// GRPC获取设备区域信息
	deviceReq := &devicec.LocationListReq{}
	deviceRes, err := deviceClient.LocationList(context.Background(), deviceReq)
	areaIDList := []string{}
	if deviceRes != nil && deviceRes.Code == 0 && err == nil {
		for _, v := range deviceRes.List {
			LocationMap[v.Id] = v.Name
			areaIDList = append(areaIDList, v.ProvinceId)
			areaIDList = append(areaIDList, v.CityId)
			areaIDList = append(areaIDList, v.DistrictId)
		}
	}
	// GRPC获取省市区名称
	var req system_admin.AreaLisRequest
	req.AreaIDs = areaIDList
	res, err1 := SystemAdminClient.AreaList(context.Background(), &req)
	if err1 != nil {
		logx.Error(context.Background(), "areas error", logx.Any("res", res), logx.Any("err", err.Error()))
		return
	}
	for _, v := range res.Areas {
		AreaNameMap[v.ID] = v.Name
	}
	for k, v := range Log {
		// grpc获取机器名称
		req := &devicec.DeviceDetailReq{}
		req.IdentificationCode = v.SalesID
		res, _ := deviceClient.DeviceDetail(context.Background(), req)
		if res != nil && res.Device != nil {
			Log[k].MerchantID = res.Device.MerchantId
			if v.RobotName == "" {
				Log[k].RobotName = res.Device.RobotId
			}
			if location, ok := LocationMap[res.Device.LocationId]; ok {
				Log[k].Location = location
			}
			if province, ok := AreaNameMap[res.Device.ProvinceId]; ok {
				Log[k].Province = province
			}
			if city, ok := AreaNameMap[res.Device.CityId]; ok {
				Log[k].City = city
			}
			if district, ok := AreaNameMap[res.Device.DistrictId]; ok {
				Log[k].District = district
			}
		}
	}
	// 商户名称
	var merchantIds = []string{}
	for _, v := range Log {
		if !lo.Contains(merchantIds, v.MerchantID) {
			merchantIds = append(merchantIds, v.MerchantID)
		}
	}
	merchantReq := &system_admin.MerchantNameReq{
		MerchantIds: merchantIds,
	}
	merchantNameMapRes, err1 := SystemAdminClient.MerchantName(ctx, merchantReq)
	if err1 != nil {
		return
	}
	for k, v := range Log {
		if merchantNameMapRes != nil && merchantNameMapRes.MerchantNameMap != nil {
			if merchantName, ok := merchantNameMapRes.MerchantNameMap[v.MerchantID]; ok {
				Log[k].MerchantName = merchantName
			}
		}
	}
	return
}

// 补货记录详情列表
func (r RobotInfoService) LogDetail(ctx context.Context, query *dal.Query, logID int64) (Log []*models.MaSaleInfoLogDetail, Count int64, err error) {
	Log, Count, err = dao.SaleInfoLogDetail{}.List(ctx, query, logID)
	return
}
